package com.diver.flinkdemo.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diver.flinkdemo.config.PropsConfig;
import com.diver.flinkdemo.dto.xxt.DeviceModeVO;
import com.diver.flinkdemo.dto.xxt.StudentCardBindingsDto;
import com.diver.flinkdemo.entity.PushData;
import com.diver.flinkdemo.entity.Trd.zgyzh.UniversalReply;
import com.diver.flinkdemo.entity.xxt.*;
import com.diver.flinkdemo.enums.MessageEnum;
import com.diver.flinkdemo.enums.StuCardTypeEnum;
import com.diver.flinkdemo.service.*;
import com.diver.flinkdemo.service.impl.*;
import com.diver.flinkdemo.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

@Slf4j
public class BaseController {
    private Logger logger = LoggerFactory.getLogger(getClass());

    protected PropsConfig propsConfig;
    private IRedisService redisService = new RedisServiceImpl();
    private ILocationInfoService locationInfoService = new LocationInfoServiceImpl();
    private ILastLocationService lastLocationService = new LastLocationServiceImpl();
    protected IDayExerciseService dayExerciseService = new DayExerciseServiceImpl();
    protected IMonthExerciseService monthExerciseService = new MonthExerciseServiceImpl();
//    private KafkaTemplate kafkaTemplate;

    private IStudentLivenessService studentLivenessService = new StudentLivenessServiceImpl() ;

    private ISchoolScreeningService schoolScreeningService = new SchoolScreeningServiceImpl();

    private IStudentCardService studentCardService = new StudentCardServiceImpl();
    private ITerminalUnitService terminalUnitService = new TerminalUnitServiceImpl();
    private IPersonBasicInfoService personBasicInfoService = new PersonBasicInfoServiceImpl();

    private IUniversalReplyService universalReplyService = new UniversalReplyServiceImpl();

    private IMoreSettingService moreSettingService = new MoreSettingService();
    private IDeviceModeService deviceModeService = new DeviceModeServiceImpl();
    private ISecurityAreaService securityAreaService = new SecurityAreaService();
    private IStudentGuardSettingService studentGuardSettingService = new StudentGuardSettingServiceImpl();
    private IMessageService messageService = new MessageService();
    private IUserStudentCardService userStudentCardService = new UserStudentCardService();
    private IFenceService fenceService = new FenceServiceImpl();
    private String dapApiPrefix;

    protected TerminalUnit getOneByCardNum(String stuId,int cardType) {
        TerminalUnit terminalUnit = terminalUnitService.getOneByCardNum(stuId,cardType);
        if (null != terminalUnit) {
            return terminalUnit;
        }
        return null;
    }

    protected UniversalReply getUniversalReply(String imei, int commandType, String distributionChannel){
        log.info("壹教云回复指令获取入参:imei{}",imei);
        UniversalReply universalReply = universalReplyService.getUniversalReply(imei, commandType, distributionChannel);
        log.info("壹教云回复指令获取反参:universalReply{}",universalReply);
        return universalReply;
    }

    protected Boolean updateUniversalReply(String id){
        log.info("壹教云回复指令修改入参:id{}",id);
        Boolean result = universalReplyService.updateUniversalReply(id);
        log.info("壹教云回复指令获取反参:result{}",result);
        return result;
    }

    protected MoreSetting getSettingByImei(String imei) {
        List<MoreSetting> settings = redisService.getList(CommonResource.CARD_SETTING_LIST, MoreSetting.class);
        if (settings!=null && !settings.isEmpty()) {
            for (MoreSetting setting : settings) {
                if (null == setting) continue;
                if (setting.getCardNum().equals(imei)) {
                    logger.info("get setting from redis {}，modetype:{}", imei, setting.getModeId());
                    return setting;
                }
            }
        } else {
            settings = new ArrayList<>();
        }
        MoreSetting setting = moreSettingService.getSettingByImei(imei);
        if (null != setting) {
            logger.info("get setting from db {}，modetype:{}", imei, setting.getModeId());
            settings.add(setting);
            redisService.set(CommonResource.CARD_SETTING_LIST, settings);
            return setting;
        }
        return new MoreSetting();
    }

    protected List<DeviceModeVO> getSchoolMode(String schoolId) {
        String key = CommonResource.SCHOOL_MODE_LIST + schoolId;
        List<DeviceModeVO> modes = redisService.getList(key, DeviceModeVO.class);
        if (modes == null || modes.isEmpty()) {
            modes = deviceModeService.getSchoolMode(schoolId);
            if (modes != null || !modes.isEmpty()) {
                redisService.set(key, modes);
            }
        }
        return modes;
    }

    protected LocationInfo getPreLocationInfo(String curStamp, String cardNum) {
        String key = CommonResource.PRE_LOCATION_KEY + cardNum;
        LocationInfo preLocationInfo = (LocationInfo) redisService.get(key, LocationInfo.class);
        if (null == preLocationInfo) {
            long stamp = Long.parseLong(curStamp);
            preLocationInfo = locationInfoService.getPreLocationInfo(stamp, cardNum);
        }
        return preLocationInfo;
    }

    protected List<Fence> getSecurityAreas(String personId) {
        String key = CommonResource.SECURITY_AREA_LIST + "_" + personId;
        List<Fence> fenceList = redisService.getList(key, Fence.class);
        if (fenceList == null || fenceList.isEmpty()) {
            logger.info("get securityAreas from businessClient {}", personId);
            fenceList = fenceService.getFenceByPersonId(personId);
//            securityAreas = securityAreaService.getAreaByStudentCardId(stuId);
//            redisService.set(key, securityAreas);
            redisService.set(key, fenceList);
        }
        return fenceList;
    }

//    /**
//     * 发送异常信息短信
//     *
//     * @param locationInfo
//     * @throws Exception
//     */
//    public void sendMessage(LocationInfo locationInfo, Integer type, StudentCard studentCard) throws Exception {
//        Integer isSend = studentCard.getIsSend();
//        String phone = studentCard.getContactsPhone();
//        String appMarket = studentCard.getAppMarket();
//        String signature = CommonResource.CHANNEL_GBG.equals(appMarket) ? CommonResource.SIGNATURE_GBG : CommonResource.SIGNATURE_XXT;
//        if (null != isSend && isSend == 0 && DataValidationUtil.isMobile(phone)) {//短信开关判断
//            String location = locationInfo.getAddress(), lat = locationInfo.getLat(), lng = locationInfo.getLon();
//            if (StringUtils.isBlank(location)) {
//                if ((StringUtils.isNotBlank(lat) && !"0".equals(lat)) && (StringUtils.isNotBlank(lng) && !"0".equals(lng))) {
//                    location = GaoDeMapUtil.getAddressByLonLat(lng, lat);
//                }
//            }
//            String name = studentCard.getName();
//            String msg = signature + (StringUtils.isBlank(name) ? studentCard.getImei() : name);
//            if (MessageEnum.SOS.getType() == type) {//SOS，5分钟内只发一条
//                String key = CommonResource.SMSTIME_SOS_KEY + studentCard.getId();
//                long effectiveTime = CommonResource.EFFECTIVE_TIME_SOSSMSTIME;
//                if (StringUtils.isBlank(location)) {
//                    key = CommonResource.SMSTIME_SOS_KEY_NOXY + studentCard.getId();
//                    msg += "按了紧急求助按钮，请及时关注哦~";
//                } else {
//                    msg += "按了紧急求助按钮，当前在" + location + "位置，请及时关注哦~";
//                }
//                Long preTime = (Long) redisService.get(key, Long.class), now = System.currentTimeMillis();
//                if (null == preTime || (now - preTime) / 1000 > effectiveTime) {
//                    redisService.set(key, now);
//                    SendSmsUtil.smsSend(phone, msg);
//                }
//            } else {
//                if (StringUtils.isBlank(location)) {
//                    return;
//                }
//                if (MessageEnum.LEAVE_SECURITY_AREA.getType() == type) {
//                    SendSmsUtil.smsSend(phone, msg + "离开了安全区域，当前位置在" + location + "附近,请及时关注哦~");
//                } else if (MessageEnum.BACKTO_SECURITY_AREA.getType() == type) {
//                    SendSmsUtil.smsSend(phone, msg + "回到了安全区域，当前位置在" + location);
//                } else if (MessageEnum.IN_DANGER_AREA.getType() == type) {
//                    SendSmsUtil.smsSend(phone, msg + "进入了疫情区域，当前位置在" + location + "附近,请及时关注哦~");
//                } else if (MessageEnum.LEAVE_DANGER_AREA.getType() == type) {
//                    SendSmsUtil.smsSend(phone, msg + "从疫情区域出来了，当前位置在" + location);
//                } else {//其他异常信息一天只发一次
//                    long nowTime = System.currentTimeMillis();
//                    QueryParams params = new QueryParams();
//                    params.addParameter("deleteFlag", 0);
//                    params.addParameter("studentCardId", locationInfo.getStudentCardId());
//                    params.addParameterByRange("createTime", ObjectUtils.dayMinMills(nowTime), ObjectUtils.dayMaxMills(nowTime));
//                    List<Message> messages = trajectoryClient.queryMessageList(params);
//                    if (messages.isEmpty()) {
//                        if (MessageEnum.LONGSTAY.getType() == type) {
//                            SendSmsUtil.smsSend(phone, msg + "已在" + location + "附近停留了超过30分钟，请及时关注哦~");
//                        }
//                        if (MessageEnum.DEVIATIONTRAJECTORY.getType() == type) {
//                            String personType = studentCard.getPersonType();
//                            if("2".equals(personType)) {
//                                SendSmsUtil.smsSend(phone, msg + "今天在行走途中偏离了日常轨迹，当前在" + location + "附近，请及时关注哦~");
//                            } else {
//                                SendSmsUtil.smsSend(phone, msg + "今天在上学/放学途中偏离了日常轨迹，当前在" + location + "附近，请及时关注哦~");
//                            }
//                        }
//                    }
//                }
//            }
//        }
//    }

    //设置安全区域信息
    protected void setSafetyInfo(LocationInfo locationInfo, TerminalUnit terminalUnit,String personId) {
        Integer isSafety = locationInfo.getIsSafety();
//        String stuId = terminalUnit.getCardNum();
//        logger.info("setSafetyInfo===>{}, isSafety:{}", stuId, isSafety);
        if (null == isSafety) {
            String cardType = terminalUnit.getTerminalSeries();
            if (StuCardTypeEnum.XTC0.getType().equals(cardType) || StuCardTypeEnum.XTC1.getType().equals(cardType) || StuCardTypeEnum.XTC40.getType().equals(cardType)|| StuCardTypeEnum.XTC2.getType().equals(cardType)) {
                List<Fence> fenceList = getSecurityAreas(personId);
                if (fenceList!=null && !fenceList.isEmpty()) {
                    for (Fence sa : fenceList) {
                        double distance = ObjectUtils.getDistanceMeter(sa.getCircleLat(), sa.getCircleLon(), locationInfo.getLat(), locationInfo.getLon());
                        BigDecimal dt = new BigDecimal(distance), radius = new BigDecimal(sa.getCircleRadius());
                        if (dt.compareTo(radius) <= 0) {
                            locationInfo.setIsSafety(1);
                            locationInfo.setExceptionMsg("在" + sa.getFenceName() + "附近");
                            locationInfo.setFenceId(sa.getId());
                            return;
                        }
                    }
                }
            }
            locationInfo.setIsSafety(0);
        } else if (1 == isSafety && StringUtils.isNotBlank(locationInfo.getSafetyName())) {//处理在除 异常信息以外 “在**附近”提示（是否在安全区域内提示）
            locationInfo.setExceptionMsg("在" + locationInfo.getSafetyName() + "附近");
        }
    }

    //获取当前安全区域
    protected List<Wifi> getNowSecurityArea(LocationInfo locationInfo) {
        if (null != locationInfo && StringUtils.isNotEmpty(locationInfo.getFenceId())){
            return securityAreaService.getWifiInfoByGuardSettingAreaId(locationInfo.getFenceId());
        }
        return new ArrayList<>();
    }
    void AsyncExecuteHandleSecurityArea(LocationInfo locationInfo, TerminalUnit terminalUnit) {
        log.info("AsyncExecuteHandleSecurityArea线程创建成功，即将执行任务");
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture.supplyAsync(new Supplier<Void>() {
            @Override
            public Void get() {
                try {
//                    handleSecurityArea(locationInfo,terminalUnit);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return null;
            }
        }, executorService);
        log.info("AsyncExecuteHandleSecurityArea线程执行完成，即将结束线程");
        executorService.shutdown();
        log.info("AsyncExecuteHandleSecurityArea线程关闭");
    }
    //进出安全区域处理
//    @Async
    protected PushData handleSecurityArea(LocationInfo locationInfo, TerminalUnit terminalUnit,PushData pushData) throws Exception {
        //查询前一条上报数据
        String cardNum = terminalUnit.getCardNum();
        logger.info("---------安全区域判断{},msgId:{}", cardNum, locationInfo.getMsgId());
        String key = CommonResource.PRE_LOCATION_KEY + cardNum;
        LocationInfo preLocationInfo = getPreLocationInfo(locationInfo.getStamp(), cardNum);
        String lat = locationInfo.getLat(), lng = locationInfo.getLon();
        int isSafety = locationInfo.getIsSafety() == null ? 0 : locationInfo.getIsSafety();
        int isSafetyPre = (preLocationInfo == null || preLocationInfo.getIsSafety() == null) ? 0 : preLocationInfo.getIsSafety();
        /*todo
           判断定位数据中的imei是否开启了上学守护
        *   是-> 用上报时间判断是否属于上学守护时间段内（8个）
        *       是-> 判断是否离开或到达安全区域，是否断连wifi，推送模板消息
            否-> 走正常围栏流程*/

        StudentCardGuardSetting guardSettingOfOpen = studentGuardSettingService.getGuardSettingOfOpen(terminalUnit.getCardNum());
        List<Wifi> homeWifiList = new ArrayList<>();
        List<Wifi> schoolWifiList = new ArrayList<>();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
        String nowDate = simpleDateFormat.format(new Date());
        Date nowTime = simpleDateFormat.parse(nowDate);
        Date[] moArriveRange = new Date[2];
        Date[] moLeaveRange = new Date[2];
        Date[] afArriveRange = new Date[2];
        Date[] afLeaveRange = new Date[2];
        if (guardSettingOfOpen!=null) {
            logger.info("开启了上学守护{}",cardNum);
            homeWifiList = securityAreaService.getWifiInfoByGuardSettingAreaId(guardSettingOfOpen.getHomeFenceId());
            logger.info("homeWifiList{}",homeWifiList);
            schoolWifiList = securityAreaService.getWifiInfoByGuardSettingAreaId(guardSettingOfOpen.getSchoolFenceId());
            //获取该学生证绑定的学校的wifi信息
//            String getSchoolWifiByImeiData = authClient.getSchoolWifiByImei();
//            ApiResult apiResult = JSON.parseObject(getSchoolWifiByImeiData, ApiResult.class);
//            ArrayList<Wifi> result = (ArrayList<Wifi>) apiResult.getResult();
//            if (!result.isEmpty()) {
//                schoolWifiList.addAll(result);
//            }
            logger.info("schoolWifiList{}",schoolWifiList);
            if(StringUtils.isNotBlank(guardSettingOfOpen.getMoArriveSchoolRange())) {
                logger.info("-----------1");
                String[] dateRange = guardSettingOfOpen.getMoArriveSchoolRange().split("-");
                moArriveRange[0] = simpleDateFormat.parse(dateRange[0]);
                moArriveRange[1] = simpleDateFormat.parse(dateRange[1]);
            }
            if (StringUtils.isNotBlank(guardSettingOfOpen.getMoLeaveSchoolRange())) {
                logger.info("------------2");
                String[] dateRange = guardSettingOfOpen.getMoLeaveSchoolRange().split("-");
                moLeaveRange[0] = simpleDateFormat.parse(dateRange[0]);
                moLeaveRange[1] = simpleDateFormat.parse(dateRange[1]);
            }
            if (StringUtils.isNotBlank(guardSettingOfOpen.getAfArriveSchoolRange())) {
                logger.info("-------------3");
                String[] dateRange = guardSettingOfOpen.getAfArriveSchoolRange().split("-");
                afArriveRange[0] = simpleDateFormat.parse(dateRange[0]);
                afArriveRange[1] = simpleDateFormat.parse(dateRange[1]);
            }
            if (StringUtils.isNotBlank(guardSettingOfOpen.getAfLeaveSchoolRange())) {
                logger.info("-------------4");
                String[] dateRange = guardSettingOfOpen.getAfLeaveSchoolRange().split("-");
                afLeaveRange[0] = simpleDateFormat.parse(dateRange[0]);
                afLeaveRange[1] = simpleDateFormat.parse(dateRange[1]);
            }
        }
        logger.info("preLocationInfo: {}",preLocationInfo);
        logger.info("locationInfo: {}",locationInfo);
        logger.info("guardSetting: {}",guardSettingOfOpen);
        //上午到校守护时间段判断
        if (guardSettingOfOpen!=null && "1".equals(guardSettingOfOpen.getStatus()) && guardSettingOfOpen.getMoArriveSchoolRange()!=null && isEffectiveDate(nowTime,moArriveRange[0],moArriveRange[1]) && getRepeatDay(guardSettingOfOpen)) {
            logger.info("··········进入上午到校守护时间段判断··········");

            Date moArriveSchoolTime = simpleDateFormat.parse(guardSettingOfOpen.getMoArriveSchoolTime());
            //判断当前时间是否处于守护时间段内
            if (isEffectiveDate(nowTime,moArriveRange[0],moArriveSchoolTime)) {
                //判断家庭安全区域是否绑定了wifi
                if (!homeWifiList.isEmpty()) {
                    logger.info("(判断上午是否离家)家庭安全区域已设置wifi{}",cardNum);
                    //判断上午是否离家
                    if (checkWifiIfConnect(homeWifiList,locationInfo) || (isSafety == 1 && Objects.equals(locationInfo.getFenceId(), guardSettingOfOpen.getHomeFenceId()))) {
                        logger.info("{}上午未离开家", cardNum);
                        pushData = sendMessageOfGuardSetting("ifLeaveHome", locationInfo, terminalUnit, MessageEnum.NOT_LEAVE_HOME_AREA.getType(), pushData);
                    }
//                    if (isEffectiveDate(nowTime,moArriveRange[0],moArriveSchoolTime)) {
//
//                    }
                } else {//没有绑定wifi，只判断围栏逻辑
                    logger.info("(判断上午是否离家)家庭安全区域未设置wifi{}",cardNum);
                    if (isSafety == 1 && Objects.equals(locationInfo.getFenceId(), guardSettingOfOpen.getHomeFenceId())) {
                        logger.info("{}上午未离开家", cardNum);
                        pushData = sendMessageOfGuardSetting("ifLeaveHome",locationInfo,terminalUnit,MessageEnum.NOT_LEAVE_HOME_AREA.getType(),pushData);
                    }
//                    if (isEffectiveDate(nowTime,moArriveRange[0],moArriveSchoolTime)) {
//
//                    }
                }

            }
            if (isEffectiveDate(nowTime,moArriveSchoolTime,moArriveRange[1])) {
                //判断是否到校
                if (!schoolWifiList.isEmpty()) {
                    if (!checkWifiIfConnect(schoolWifiList,locationInfo) && isSafety == 0 || (isSafety==1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getSchoolFenceId()))) {
                        logger.info("{}上午未到达学校", cardNum);
                        pushData = sendMessageOfGuardSetting("ifArriveSchool",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_SCHOOL_AREA.getType(),pushData);
                    }

                }else {
                    if (isSafety == 0 || (isSafety==1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getSchoolFenceId()))) {
                        logger.info("{}上午未到达学校", cardNum);
                        pushData = sendMessageOfGuardSetting("ifArriveSchool",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_SCHOOL_AREA.getType(),pushData);
                    }
                }
            }

            //添加推送省中台信息
            String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
            //todo push szt
//            saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
            redisService.remove(crkey);
        }else if (guardSettingOfOpen!=null && "1".equals(guardSettingOfOpen.getStatus()) && guardSettingOfOpen.getAfArriveSchoolRange()!=null && isEffectiveDate(nowTime,afArriveRange[0],afArriveRange[1]) && getRepeatDay(guardSettingOfOpen)) {
            //下午到校守护时间段判断
            logger.info("··········进入下午到校守护时间段判断··········");
            Date afArriveTime = simpleDateFormat.parse(guardSettingOfOpen.getAfArriveSchoolTime());
            if (isEffectiveDate(nowTime,afArriveRange[0],afArriveTime)) {
                if (!homeWifiList.isEmpty()) {
                    logger.info("(判断下午是否离家)家庭安全区域已设置wifi{}",cardNum);
                    //判断下午是否离家
                    if (checkWifiIfConnect(homeWifiList,locationInfo) || (isSafety == 1 && Objects.equals(locationInfo.getFenceId(), guardSettingOfOpen.getHomeFenceId()))) {
                        logger.info("{}下午未离开家", cardNum);
                        pushData = sendMessageOfGuardSetting("ifAfLeaveHome",locationInfo,terminalUnit,MessageEnum.NOT_LEAVE_HOME_AREA.getType(),pushData);
                    }

                }else {
                    logger.info("(判断下午是否离家)家庭安全区域未设置wifi{}",cardNum);
                    if (isSafety == 1 && Objects.equals(locationInfo.getFenceId(), guardSettingOfOpen.getHomeFenceId())) {
                        logger.info("{}下午未离开家", cardNum);
                        pushData = sendMessageOfGuardSetting("ifAfLeaveHome",locationInfo,terminalUnit,MessageEnum.NOT_LEAVE_HOME_AREA.getType(),pushData);
                    }
                }

            }
            if (isEffectiveDate(nowTime,afArriveTime,afArriveRange[1])) {
                //判断下午是否未到校
                if (!schoolWifiList.isEmpty()) {
                    if (!checkWifiIfConnect(schoolWifiList,locationInfo) && isSafety ==0 || (isSafety == 1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getSchoolFenceId()))) {
                        logger.info("{}下午未到校", cardNum);
                        pushData = sendMessageOfGuardSetting("ifAfArriveSchool",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_SCHOOL_AREA.getType(),pushData);
                    }
                }else {
                    if (isSafety == 0 || (isSafety == 1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getSchoolFenceId()))){
                        logger.info("{}下午未到校", cardNum);
                        pushData = sendMessageOfGuardSetting("ifAfArriveSchool",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_SCHOOL_AREA.getType(),pushData);
                    }
                }
            }

            //添加推送省中台信息
            String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
            //todo push szt
//            saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
            redisService.remove(crkey);
        }
        if (guardSettingOfOpen!=null && "1".equals(guardSettingOfOpen.getStatus()) && guardSettingOfOpen.getMoLeaveSchoolRange()!=null && isDateEqualOrAfter(nowTime,moLeaveRange[1]) &&  getRepeatDay(guardSettingOfOpen)) {
            //上午离校守护时间段判断
            logger.info("··········进入上午离校守护时间段判断··········");
            Date moLeaveTime = simpleDateFormat.parse(guardSettingOfOpen.getMoLeaveSchoolTime());
            //判断上午是否到家
            if (!homeWifiList.isEmpty()) {
                logger.info("(上午是否到家)家庭安全区域已设置wifi{}",cardNum);
                if (isSafety == 0 && !checkWifiIfConnect(homeWifiList,locationInfo) || (isSafety==1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getHomeFenceId()))) {
                    logger.info("{}上午未到家", cardNum);
                    pushData = sendMessageOfGuardSetting("ifArriveHome",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_HOME_AREA.getType(),pushData);
                }
            }else {
                logger.info("(上午是否到家)家庭安全区域未设置wifi{}",cardNum);
                if (isSafety == 0 || (isSafety==1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getHomeFenceId()))){
                    logger.info("{}上午未到家", cardNum);
                    pushData = sendMessageOfGuardSetting("ifArriveHome",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_HOME_AREA.getType(),pushData);
                }
            }
//            if (isEffectiveDate(nowTime,moLeaveTime,moLeaveRange[1])) {
//
//            }
            //添加推送省中台信息
            String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
            //todo push szt
//            saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
            redisService.remove(crkey);
        }
        if (guardSettingOfOpen!=null && "1".equals(guardSettingOfOpen.getStatus())&& guardSettingOfOpen.getAfLeaveSchoolRange()!=null && isDateEqualOrAfter(nowTime,afLeaveRange[1]) && getRepeatDay(guardSettingOfOpen)) {
            //下午离校守护时间段判断
            logger.info("··········进入下午离校守护时间段判断··········");
            Date afLeaveTime = simpleDateFormat.parse(guardSettingOfOpen.getAfLeaveSchoolTime());
            if (!homeWifiList.isEmpty()) {
                logger.info("(判断下午是否未到家)家庭安全区域已设置wifi{}",cardNum);
                //判断下午是否未到家
                if (!checkWifiIfConnect(homeWifiList,locationInfo) && isSafety == 0 || (isSafety == 1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getHomeFenceId()))) {
                    logger.info("{}下午未到家", cardNum);
                    pushData = sendMessageOfGuardSetting("ifAfArriveHome",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_HOME_AREA.getType(),pushData);
                }
            }else {
                logger.info("(判断下午是否未到家)家庭安全区域未设置wifi{}",cardNum);
                //判断下午是否未到家
                if (isSafety == 0 || (isSafety == 1 && !Objects.equals(locationInfo.getFenceId(),guardSettingOfOpen.getHomeFenceId()))) {
                    logger.info("{}下午未到家", cardNum);
                    pushData = sendMessageOfGuardSetting("ifAfArriveHome",locationInfo,terminalUnit,MessageEnum.NOT_ARRIVE_HOME_AREA.getType(),pushData);
                }
            }
//            if (isEffectiveDate(nowTime,afLeaveTime,afLeaveRange[1])) {
//
//            }
            //添加推送省中台信息
            String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
            //todo push szt
//            saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
            redisService.remove(crkey);
        }

//        韩飞说C1K1不设置wifi，也不用屏蔽进出围栏wifi判断
//        C40围栏判断
        if (StuCardTypeEnum.XTC40.getType().equals(terminalUnit.getTerminalSeries()) || StuCardTypeEnum.XTC2.getType().equals(terminalUnit.getTerminalSeries())){
            logger.info("进入C40,C2K1类型设备围栏判断...");
            if (1 == isSafetyPre && 0 == isSafety) {//离开安全区域提示
                //进出围栏，判断是否定位漂移，漂移则不推送消息
                if (! isChangeSafetyArea(locationInfo, terminalUnit, preLocationInfo)){
                    String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
                    logger.info("{}判断离开安全区域", cardNum);
                    //changeMode(studentCard, isSafety, false);//模式切换
                    // todo 添加推送省中台信息
//                        saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
                    logger.info("{}出围栏校验为true", cardNum);
                    //判断该围栏是不是上学守护的围栏
                    if (StringUtils.isNotEmpty(preLocationInfo.getFenceId()) && null != guardSettingOfOpen && "1".equals(guardSettingOfOpen.getStatus()) && preLocationInfo.getFenceId().equals(guardSettingOfOpen.getHomeFenceId())){
                        //出上学守护的家
//                            sendMessageOfGuardSetting("ifLeaveHome",locationInfo,studentCard,MessageEnum.LEAVE_HOME_AREA.getType());
                        logger.info("即将推送上学守护离家消息{}",cardNum);
                        pushData.setUdMsgType(MessageEnum.LEAVE_HOME_AREA.getType());
//                            messageService.setGuardSettingMessage(cardNum, studentCard.getName(),locationInfo.getLat(), locationInfo.getLon(),locationInfo.getUploadTime(), MessageEnum.LEAVE_HOME_AREA.getType(), locationInfo.getAddress(), locationInfo.getMac());
                    } else if (StringUtils.isNotEmpty(preLocationInfo.getFenceId()) && null != guardSettingOfOpen && "1".equals(guardSettingOfOpen.getStatus()) && preLocationInfo.getFenceId().equals(guardSettingOfOpen.getSchoolFenceId())){
                        //出上学守护的学校
                        logger.info("即将推送上学守护离校消息{}",cardNum);
                        pushData.setUdMsgType(MessageEnum.LEAVE_SCHOOL_AREA.getType());
//                            sendMessageOfGuardSetting("ifLeaveSchool",locationInfo,studentCard,MessageEnum.LEAVE_SCHOOL_AREA.getType());
//                            messageService.setGuardSettingMessage(studentCardId, studentCard.getName(),locationInfo.getLat(), locationInfo.getLon(),locationInfo.getUploadTime(), MessageEnum.LEAVE_SCHOOL_AREA.getType(), locationInfo.getAddress(), locationInfo.getMac());
                    }else {
                        pushData.setUdMsgType(MessageEnum.LEAVE_SECURITY_AREA.getType());
//                            messageService.setMessage(studentCard, locationInfo.getUploadTime(), lat, lng, MessageEnum.LEAVE_SECURITY_AREA.getType(), locationInfo.getElectricity(), locationInfo.getAddress(), locationInfo.getMac());
                    }
                    redisService.remove(crkey);
                }
            } else if (0 == isSafetyPre && 1 == isSafety) {//回到安全区域提示
                logger.info("{}判断回到安全区域", cardNum);
                //todo 添加推送省中台信息
//                    saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
                //判断该围栏是不是上学守护的围栏
                if (StringUtils.isNotEmpty(locationInfo.getFenceId()) && null != guardSettingOfOpen && "1".equals(guardSettingOfOpen.getStatus()) && locationInfo.getFenceId().equals(guardSettingOfOpen.getHomeFenceId())){
                    //进上学守护的家
                    logger.info("即将推送上学守护到家消息{}",cardNum);
                    pushData.setUdMsgType(MessageEnum.ARRIVE_HOME_AREA.getType());
                } else if (StringUtils.isNotEmpty(locationInfo.getFenceId()) && null != guardSettingOfOpen && "1".equals(guardSettingOfOpen.getStatus()) && locationInfo.getFenceId().equals(guardSettingOfOpen.getSchoolFenceId())){
                    //进上学守护的学校
                    logger.info("即将推送上学守护到校消息{}",cardNum);
                    pushData.setUdMsgType(MessageEnum.ARRIVE_SCHOOL_AREA.getType());
                }else {
                    pushData.setUdMsgType(MessageEnum.BACKTO_SECURITY_AREA.getType());
                }
            }
        }else {
            //普通围栏逻辑
            logger.info("进入非C40,C2K1类型设备围栏判断...");
            if (1 == isSafetyPre && 0 == isSafety) {//离开安全区域提示
                String crkey = CommonResource.PRE_COMMAND_CR + cardNum;
                logger.info("{}判断离开安全区域", cardNum);
                //changeMode(studentCard, isSafety, false);//模式切换
                //todo 添加推送省中台信息
//                    saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
                pushData.setUdMsgType(MessageEnum.LEAVE_SECURITY_AREA.getType());
                redisService.remove(crkey);
            } else if (0 == isSafetyPre && 1 == isSafety) {//回到安全区域提示
                logger.info("{}判断回到安全区域", cardNum);
                //changeMode(studentCard, isSafety, false);//模式切换
                //todo 添加推送省中台信息
//                    saveStudentLiveness(terminalUnit, "dzwlyj", "电子围栏预警", "");
                pushData.setUdMsgType(MessageEnum.BACKTO_SECURITY_AREA.getType());
            }
        }
        logger.info("------记录当前上报的位置信息到redis，{}",cardNum);
        redisService.set(key, locationInfo);//把当前位置数据设置到缓存
        return pushData;
    }

    private PushData sendMessageOfGuardSetting(String guardStr,LocationInfo locationInfo,TerminalUnit terminalUnit,Integer type,PushData pushData) {
        String cardNum = terminalUnit.getCardNum();
        String guardKey = CommonResource.GUARD_SETTING_MESSAGE+guardStr+cardNum;
        Integer ifSend = (Integer) redisService.get(guardKey, Integer.class);
        if (ifSend==null || ifSend <1) {
            pushData.setUdMsgType(type);
            redisService.set(guardKey, 1800L, 1);
//            messageService.setGuardSettingMessage(cardNum, studentCard.getName(),locationInfo.getLat(), locationInfo.getLon(),locationInfo.getUploadTime(), type, locationInfo.getAddress(), locationInfo.getMac());
            logger.info("{}执行完上学守护消息发送流程", cardNum);
        }else {
            logger.info("{}已推送过该消息，不执行上学守护消息发送流程",cardNum);
        }
        return pushData;
    }
    private Boolean  isChangeSafetyArea(LocationInfo locationInfo, TerminalUnit terminalUnit,LocationInfo preLocationInfo){
        boolean result = false;
        String wifi = locationInfo.getWifi();
        logger.info("出围栏设备搜到的wifi{}", wifi);
        List<Wifi> wifiList = getNowSecurityArea(preLocationInfo);
        if(null != wifiList && wifiList.size() > 0){
            //判断上报的wifi是否在设置的wifi列表中
            for (Wifi uploadWifi:wifiList) {
                if (StringUtils.isNotEmpty(uploadWifi.getMac())){
                    result = wifi.contains(uploadWifi.getMac());
                    if (result){
                        break;
                    }
                }
            }
        }
        logger.info("出围栏判断是否搜索到wifi{}", result);
        return result;
    }

    private boolean checkWifiIfConnect(List<Wifi> wifiList,LocationInfo locationInfo) {
        boolean result = false;
        String wifi = locationInfo.getWifi();
        //判断上报的wifi是否在设置的wifi列表中
        for (Wifi uploadWifi:wifiList) {
            result = wifi.contains(uploadWifi.getMac());
            if (result){
                break;
            }
        }
        return result;
    }

    //调用数据分析平台接口校验可信度（0出围栏，1进围栏）
    protected boolean checkConfidence(String personId, String msgId, String fenceId, int type) {
        logger.info("---------进出围栏可信度校验(0出，1进):{}，围栏id:{}", type, fenceId);
        List<Fence> securityAreas = getSecurityAreas(personId);
        if (securityAreas!=null && !securityAreas.isEmpty()) {
            for (Fence sa : securityAreas) {
                if (sa.getId().equals(fenceId)) {
                    try {
//                        String url = propsConfig.getDapApiPrefix() + ApiSuffix.DAP_GPS_CONFIDENCE;
                        log.info("dapApiPrefix:{}",dapApiPrefix);
                        String url = dapApiPrefix + ApiSuffix.DAP_GPS_CONFIDENCE;
                        Map<String, String> param = new HashMap<>();
                        param.put("msgId", msgId);
                        param.put("checkType", String.valueOf(type));//0出，1进
                        param.put("fenceLongitude", sa.getCircleLon());//围栏经度
                        param.put("fenceLatitude", sa.getCircleLat());//围栏纬度
                        param.put("fenceRadius", String.valueOf(sa.getCircleRadius()));//围栏半径
                        param.put("fenceTurnBackWidth", String.valueOf(CommonResource.SECURITY_AREA_BUFFER));//围栏缓冲区
                        logger.info("doGet请求地址:{}", url);
                        String result = HttpUrlClient.doGet(url, param);
                        logger.info("doGet result:{}", result);
                        if (StringUtils.isNotBlank(result)) {
                            JSONObject obj = JSONObject.parseObject(result);
                            if (200 == obj.getIntValue("code")) {
                                JSONObject data = obj.getJSONObject("data");
                                boolean passed = data.getBoolean("passed");
                                return passed;
                            }
                        }
                    } catch (Exception e) {
                        logger.error("进出围栏可信度异常", e);
                    }
                    return true;
                }
            }
        }
        return true;
    }


    void AsyncExecuteSaveExercise(TerminalUnit terminalUnit, LocationInfo locationInfo,String schoolId) {
        log.info("AsyncExecuteSaveExercise线程创建成功，即将执行任务");
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture.supplyAsync(new Supplier<Void>() {
            @Override
            public Void get() {
                try {
                    saveExercise(terminalUnit,locationInfo,schoolId);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return null;
            }
        }, executorService);
        log.info("AsyncExecuteSaveExercise线程执行完成，即将结束线程");
        executorService.shutdown();
        log.info("AsyncExecuteSaveExercise线程关闭");
    }

    /**
     * 异步保存统计数据
     *
     * @param terminalUnit
     * @param locationInfo
     */
//    @Async
    protected void saveExercise(TerminalUnit terminalUnit, LocationInfo locationInfo,String schoolId) {
        logger.info("---------saveExercise:{}", terminalUnit.getCardNum());
        try {
            //保存运动步数
            if (!ObjectUtils.isEmpty(locationInfo.getStep()) && !locationInfo.getStep().equals("-1")) {
                log.info("saveDayExercise,studentCardId->{}",terminalUnit.getCardNum());
                saveDayExercise(terminalUnit, locationInfo,schoolId);
            }
        } catch (Exception e) {
            logger.error("saveExercise error", e);
        }
    }

    /**
     * 保存天数据
     *
     * @param terminalUnit
     * @param locationInfo
     * @return 变动步数
     */
    private int saveDayExercise(TerminalUnit terminalUnit, LocationInfo locationInfo,String schoolId) {
        int addStep = 0;//新增步数
        //查询当天是否有数据，有数据直接修改
        String step = locationInfo.getStep();
        String distance = DataUtil.getDistance(step);
        String heat = DataUtil.getHeatByStep(step);
//        QueryParams queryParams = new QueryParams();
//        queryParams.addParameter("studentCardId", studentCard.getId());
        Long createTime = DateUtil.getTodayZeroPointTimestamps(locationInfo.getUploadTime().getTime());
//        queryParams.addParameter("createTime", createTime);
        QueryWrapper<DayExercise> dayExerciseQueryWrapper = new QueryWrapper<>();
        dayExerciseQueryWrapper.eq("student_card_id", terminalUnit.getCardNum());
        dayExerciseQueryWrapper.eq("create_time",createTime);
        List<DayExercise> dayExercises = dayExerciseService.listByParams(dayExerciseQueryWrapper);
        if (dayExercises != null && dayExercises.size() > 0) {//存在更新
            log.info("day_exercise更新纪录");
            DayExercise dayExercise = dayExercises.get(0);
            addStep = Integer.valueOf(step) - Integer.valueOf(dayExercise.getStep());
            if (addStep == 0) {
                return 0;
            }
            dayExercise.setStep(step);
            dayExercise.setDistance(distance);
            dayExercise.setHeat(heat);
            //更新运动数据
            dayExerciseService.doUpdateModelByStuId(dayExercise);
        } else {//不存在添加
            log.info("day_exercise添加新纪录");
            addStep = Integer.valueOf(step);
            DayExercise dayExercise = new DayExercise();
            dayExercise.setId(UUIDUtil.uuid());
            dayExercise.setStudentCardId(terminalUnit.getCardNum());
            dayExercise.setStep(step);
            dayExercise.setDistance(distance);
            dayExercise.setHeat(heat);
            dayExercise.setSchoolId(schoolId);
//            dayExercise.setSchoolName(studentCard.getSchoolName());
//            dayExercise.setGradeId(studentCard.getGradeId());
//            dayExercise.setGradeName(studentCard.getGradeName());
//            dayExercise.setClassName(studentCard.getClassName());
            dayExercise.setCreateTime(createTime);
            //保存运动数据
            dayExerciseService.save(dayExercise);
        }
        logger.info("finish saveDayExercise,studentCardId:{}", terminalUnit.getCardNum());
        return addStep;
    }

//     模式切换 isSafety 0围栏外，1围栏内
    protected void changeMode(TerminalUnit terminalUnit, String schoolId,int isSafety, boolean isInit) {
        String imei = terminalUnit.getCardNum();
        MoreSetting setting = getSettingByImei(imei);
        //todo
//        String schoolId = schoolId;
        if (StringUtils.isNotBlank(schoolId)) {
            List<DeviceModeVO> modes = getSchoolMode(schoolId);
            if (modes!=null && !modes.isEmpty()) {
                String modeType = setting.getModeId();
                if (StringUtils.isBlank(modeType) || CommonResource.MODE_TYPE_INTELLIGENT.equals(modeType)) {
                    logger.info("智能模式处理：{}", imei);
                    for (DeviceModeVO mode : modes) {
                        Integer pos = mode.getDevicePosition();//0围栏内 1围栏外 2内外
                        if (pos != null && (2 == pos || (isSafety == 1 && pos == 0) || (isSafety == 0 && pos == 1))) {
                            LocationMode locationMode = new LocationMode();
                            locationMode.setGpsRepInterval(mode.getGpsRepInterval());
                            locationMode.setPositionFirst(0);
                            //暂时注释
//                            businessClient.sendMode(imei, studentCard.getCardType(), locationMode);
                            return;
                        }
                    }
                }
                if (isInit) {//非智能模式并且需要初始化策略，直接下发，不判断围栏
                    for (DeviceModeVO mode : modes) {
                        if (modeType.equals(mode.getId())) {
                            logger.info("初始化模式：{}，{}", imei, mode.getModeName());
                            LocationMode locationMode = new LocationMode();
                            locationMode.setGpsRepInterval(mode.getGpsRepInterval());
                            locationMode.setPositionFirst(0);
                            //暂时注释
//                            businessClient.sendMode(imei, studentCard.getCardType(), locationMode);
                            return;
                        }
                    }
                }
            }
        }
    }


    public int saveStudentLiveness(StudentCard studentCard, String opcode, String opname, String oplasttime) {
        return studentLivenessService.saveStudentLiveness(studentCard,opcode,opname,oplasttime);
    }

    public void screenAccountName(TerminalUnit terminalUnit, String distinguish) {
        terminalUnit.setIsPushSZT(false);//默认不推送
        if (distinguish == null || "".equals(distinguish)) {
            terminalUnit.setIsPushSZT(true);//为空 推送
        }
        List<StudentCardBindingsDto> studentCardBindings = userStudentCardService.getStudentCardBindings(terminalUnit.getCardNum());
        if(studentCardBindings != null && studentCardBindings.size() >= 0){
            List<String> szt = schoolScreeningService.getSchoolScreening(distinguish);
            if(szt.size() > 0){
                for (int i = 0; i<studentCardBindings.size(); i++){
                    if(szt.contains(studentCardBindings.get(i).getAccountName())){
                        terminalUnit.setIsPushSZT(true);//是筛选渠道，推送
                    }
                }
            }else{
                terminalUnit.setIsPushSZT(true);//没筛选 默认推送
            }
        }
    }
    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意三个参数的时间格式要一致
     * @param nowTime
     * @param startTime
     * @param endTime
     * @return 在时间段内返回true，不在返回false
     */
    public boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime == null || startTime == null || endTime == null) {
            return false;
        }
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);
        logger.info("********time: {},{},{}",date.getTime(),begin.getTime(),end.getTime());
        logger.info("***********inRangeTime: {}",(date.after(begin) && date.before(end)));
        return date.after(begin) && date.before(end);

    }

    public boolean isDateEqualOrAfter(Date nowTime, Date date) {
        if (nowTime == null || date == null ) {
            return false;
        }
        if (nowTime.getTime() == date.getTime()) {
            return true;
        }

        Calendar begin = Calendar.getInstance();
        begin.setTime(date);

        Calendar now = Calendar.getInstance();
        now.setTime(nowTime);

        Calendar after = Calendar.getInstance();
        after.setTime(date);
        after.add(Calendar.MINUTE,4);

        logger.info("---------isDateEqualOrAfter: begin,{};now,{};after,{}",begin.getTime(),now.getTime(),after.getTime());
        return now.after(begin) && now.before(after);
    }

    public boolean getRepeatDay(StudentCardGuardSetting guardSettingOfOpen) {
        List<String> repeatDayList = new ArrayList<>();
        if (guardSettingOfOpen.getRepeatCycle()!=null) {
            char[] chars = guardSettingOfOpen.getRepeatCycle().toCharArray();
            for (int i = 0; i<chars.length-1; i++) {
                if (chars[i] == '1') {
                    switch (i) {
                        case 0:
                            repeatDayList.add("Sunday");
                            break;
                        case 1:
                            repeatDayList.add("Monday");
                            break;
                        case 2:
                            repeatDayList.add("Tuesday");
                            break;
                        case 3:
                            repeatDayList.add("Wednesday");
                            break;
                        case 4:
                            repeatDayList.add("Thursday");
                            break;
                        case 5:
                            repeatDayList.add("Friday");
                            break;
                        case 6:
                            repeatDayList.add("Saturday");
                            break;
                    }
                }
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE",Locale.ENGLISH);
            String dayOfWeek = simpleDateFormat.format(new Date());
            logger.info("当前日期{}",dayOfWeek);
            logger.info("重复日期{}",repeatDayList);
            logger.info("repeatDayContain{} ",repeatDayList.contains(dayOfWeek));
            if (repeatDayList.contains(dayOfWeek)) {
                return true;
            }else {
                return false;
            }

        }
        return false;
    }
}
